home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
wais
/
waisgate
/
HTFormat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-09
|
11KB
|
437 lines
/* Manage different file formats HTFormat.c
** =============================
**
** Bugs:
** Not reentrant.
**
** Assumes the incoming stream is ASCII, rather than a local file
** format, and so ALWAYS converts from ASCII on non-ASCII machines.
** Therefore, non-ASCII machines can't read local files.
**
*/
/* Implements:
*/
#include "HTFormat.h"
PUBLIC float HTMaxSecs = 1e10; /* No effective limit */
PUBLIC float HTMaxLength = 1e10; /* No effective limit */
#ifdef unix
#ifdef NeXT
#define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
#else
#define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"
/* Full pathname would be better! */
#endif
#endif
#include "HTUtils.h"
#include "tcp.h"
#include "HTML.h"
#include "HTMLDTD.h"
#include "HText.h"
#include "HTAlert.h"
#include "HTList.h"
#include "HTInit.h"
/* Streams and structured streams which we use:
*/
#include "HTFWriter.h"
#include "HTPlain.h"
#include "SGML.h"
#include "HTML.h"
#include "HTMLGen.h"
PUBLIC BOOL HTOutputSource = NO; /* Flag: shortcut parser to stdout */
extern BOOL interactive;
struct _HTStream {
CONST HTStreamClass* isa;
/* ... */
};
/* Presentation methods
** --------------------
*/
PUBLIC HTList * HTPresentations = 0;
PUBLIC HTPresentation* default_presentation = 0;
/* Define a presentation system command for a content-type
** -------------------------------------------------------
*/
PUBLIC void HTSetPresentation ARGS5(
CONST char *, representation,
CONST char *, command,
float, quality,
float, secs,
float, secs_per_byte
){
HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
pres->rep = HTAtom_for(representation);
pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
pres->converter = HTSaveAndExecute; /* Fixed for now ... */
pres->quality = quality;
pres->secs = secs;
pres->secs_per_byte = secs_per_byte;
pres->rep = HTAtom_for(representation);
pres->command = 0;
StrAllocCopy(pres->command, command);
if (!HTPresentations) HTPresentations = HTList_new();
if (strcmp(representation, "*")==0) {
if (default_presentation) free(default_presentation);
default_presentation = pres;
} else {
HTList_addObject(HTPresentations, pres);
}
}
/* Define a built-in Function for a content-type
** ---------------------------------------------
*/
PUBLIC void HTSetConversion ARGS6(
CONST char *, representation_in,
CONST char *, representation_out,
HTConverter, converter,
float, quality,
float, secs,
float, secs_per_byte
){
HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
pres->rep = HTAtom_for(representation_in);
pres->rep_out = HTAtom_for(representation_out);
pres->converter = converter;
pres->command = NULL; /* Fixed */
pres->quality = quality;
pres->secs = secs;
pres->secs_per_byte = secs_per_byte;
pres->command = 0;
if (!HTPresentations) HTPresentations = HTList_new();
if (strcmp(representation_in, "*")==0) {
if (default_presentation) free(default_presentation);
default_presentation = pres;
} else {
HTList_addObject(HTPresentations, pres);
}
}
/* File buffering
** --------------
**
** The input file is read using the macro which can read from
** a socket or a file.
** The input buffer size, if large will give greater efficiency and
** release the server faster, and if small will save space on PCs etc.
*/
#define INPUT_BUFFER_SIZE 4096 /* Tradeoff */
PRIVATE char input_buffer[INPUT_BUFFER_SIZE];
PRIVATE char * input_pointer;
PRIVATE char * input_limit;
PRIVATE int input_file_number;
/* Set up the buffering
**
** These routines are public because they are in fact needed by
** many parsers, and on PCs and Macs we should not duplicate
** the static buffer area.
*/
PUBLIC void HTInitInput ARGS1 (int,file_number)
{
input_file_number = file_number;
input_pointer = input_limit = input_buffer;
}
PUBLIC char HTGetChararcter NOARGS
{
char ch;
do {
if (input_pointer >= input_limit) {
int status = NETREAD(
input_file_number, input_buffer, INPUT_BUFFER_SIZE);
if (status <= 0) {
if (status == 0) return (char)EOF;
if (TRACE) fprintf(stderr,
"HTFormat: File read error %d\n", status);
return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
}
input_pointer = input_buffer;
input_limit = input_buffer + status;
}
ch = *input_pointer++;
} while (ch == (char) 13); /* Ignore ASCII carriage return */
return FROMASCII(ch);
}
/* Stream the data to an ouput file as binary
*/
PUBLIC int HTOutputBinary ARGS2( int, input,
FILE *, output)
{
do {
int status = NETREAD(
input, input_buffer, INPUT_BUFFER_SIZE);
if (status <= 0) {
if (status == 0) return 0;
if (TRACE) fprintf(stderr,
"HTFormat: File read error %d\n", status);
return 2; /* Error */
}
fwrite(input_buffer, sizeof(char), status, output);
} while (YES);
}
/* Create a filter stack
** ---------------------
**
** If a widlcard match is made, a temporary HTPresentation
** structure is made to hold the destination format while the
** new stack is generated. This is just to pass the out format to
** MIME so far. Storing the format of a stream in the stream might
** be a lot neater.
*/
PUBLIC HTStream * HTStreamStack ARGS4(
HTFormat, format_in,
HTFormat, rep_out,
HTStream*, sink,
HTParentAnchor*, anchor)
{
HTAtom * wildcard = HTAtom_for("*");
HTPresentation temp;
if (TRACE) fprintf(stderr,
"HTFormat: Constructing stream stack for %s to %s\n",
HTAtom_name(format_in),
HTAtom_name(rep_out));
if (rep_out == WWW_SOURCE ||
rep_out == format_in) return sink;
if (!HTPresentations) HTFormatInit(); /* set up the list */
{
int n = HTList_count(HTPresentations);
int i;
HTPresentation * pres;
for(i=0; i<n; i++) {
pres = HTList_objectAt(HTPresentations, i);
if (pres->rep == format_in) {
if (pres->rep_out == rep_out)
return (*pres->converter)(pres, anchor, sink);
if (pres->rep_out == wildcard) {
temp = *pres;/* make temp conversion to needed fmt */
temp.rep_out = rep_out; /* yuk */
return (*pres->converter)(&temp, anchor, sink);
}
}
}
}
#ifdef XMOSAIC_HACK
return sink;
#else
return NULL;
#endif
}
/* Find the cost of a filter stack
** -------------------------------
**
** Must return the cost of the same stack which StreamStack would set up.
**
** On entry,
** length The size of the data to be converted
*/
PUBLIC float HTStackValue ARGS4(
HTFormat, format_in,
HTFormat, rep_out,
float, initial_value,
long int, length)
{
HTAtom * wildcard = HTAtom_for("*");
if (TRACE) fprintf(stderr,
"HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
HTAtom_name(format_in), initial_value,
HTAtom_name(rep_out));
if (rep_out == WWW_SOURCE ||
rep_out == format_in) return 0.0;
if (!HTPresentations) HTFormatInit(); /* set up the list */
{
int n = HTList_count(HTPresentations);
int i;
HTPresentation * pres;
for(i=0; i<n; i++) {
pres = HTList_objectAt(HTPresentations, i);
if (pres->rep == format_in && (
pres->rep_out == rep_out ||
pres->rep_out == wildcard)) {
float value = initial_value * pres->quality;
if (HTMaxSecs != 0.0)
value = value - (length*pres->secs_per_byte + pres->secs)
/HTMaxSecs;
return value;
}
}
}
return -1e30; /* Really bad */
}
/* Push data from a socket down a stream
** -------------------------------------
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
PUBLIC void HTCopy ARGS2(
int, file_number,
HTStream*, sink)
{
HTStreamClass targetClass;
/* Push the data, ignoring CRLF, down the stream
**
*/
targetClass = *(sink->isa); /* Copy pointers to procedures */
/* Push binary from socket down sink
*/
for(;;) {
int status = NETREAD(
file_number, input_buffer, INPUT_BUFFER_SIZE);
if (status <= 0) {
if (status == 0) break;
if (TRACE) fprintf(stderr,
"HTFormat: Read error, read returns %d\n", status);
break;
}
(*targetClass.put_block)(sink, input_buffer, status);
} /* next bufferload */
}
/* Push data from a socket down a stream STRIPPING CR
** --------------------------------------------------
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
PUBLIC void HTCopyNoCR ARGS2(
int, file_number,
HTStream*, sink)
{
HTStreamClass targetClass;
/* Push the data, ignoring CRLF, down the stream
**
*/
targetClass = *(sink->isa); /* Copy pointers to procedures */
/* Push text from telnet socket down sink
**
** @@@@@ To push strings could be faster? (especially is we
** cheat and don't ignore CR! :-}
*/
HTInitInput(file_number);
for(;;) {
char character;
character = HTGetChararcter();
if (character == (char)EOF) break;
(*targetClass.put_character)(sink, character);
}
}
/* Parse a socket given format and file number
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
PUBLIC int HTParseSocket ARGS5(
HTFormat, format_in,
HTFormat, format_out,
HTParentAnchor *, anchor,
int, file_number,
HTStream*, sink)
{
HTStream * stream;
HTStreamClass targetClass;
stream = HTStreamStack(format_in,
format_out,
sink , anchor);
if (!stream) {
char buffer[1024]; /* @@@@@@@@ */
sprintf(buffer, "Sorry, can't convert from %s to %s.",
HTAtom_name(format_in), HTAtom_name(format_out));
if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
return HTLoadError(sink, 501, buffer);
}
/* Push the data, ignoring CRLF if necessary, down the stream
**
**
** @@ Bug: This decision ought to be made based on "encoding"
** rather than on format. @@@ Whne we handle encoding.
** The current method smells anyway.
*/
targetClass = *(stream->isa); /* Copy pointers to procedures */
if (format_in == WWW_BINARY || HTOutputSource
|| strstr(HTAtom_name(format_in), "image/")
|| strstr(HTAtom_name(format_in), "video/")) { /* @@@@@@ */
HTCopy(file_number, stream);
} else { /* ascii text with CRLFs :-( */
HTCopyNoCR(file_number, stream);
}
(*targetClass.end_document)(stream);
(*targetClass.free)(stream);
return HT_LOADED;
}